package org.exoplatform.extension.exchange.service;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.KeyStore;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.TimeZone;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.jcr.Node;
import microsoft.exchange.webservices.data.Appointment;
import microsoft.exchange.webservices.data.BasePropertySet;
import microsoft.exchange.webservices.data.CalendarFolder;
import microsoft.exchange.webservices.data.ExchangeService;
import microsoft.exchange.webservices.data.FindItemsResults;
import microsoft.exchange.webservices.data.Folder;
import microsoft.exchange.webservices.data.FolderId;
import microsoft.exchange.webservices.data.Item;
import microsoft.exchange.webservices.data.ItemEvent;
import microsoft.exchange.webservices.data.ItemId;
import microsoft.exchange.webservices.data.ItemSchema;
import microsoft.exchange.webservices.data.ItemView;
import microsoft.exchange.webservices.data.PropertySet;
import microsoft.exchange.webservices.data.SearchFilter;
import microsoft.exchange.webservices.data.ServiceLocalException;
import microsoft.exchange.webservices.data.WellKnownFolderName;
import org.exoplatform.calendar.service.Calendar;
import org.exoplatform.calendar.service.CalendarEvent;
import org.exoplatform.calendar.service.CalendarService;
import org.exoplatform.calendar.service.CalendarSetting;
import org.exoplatform.calendar.service.impl.CalendarServiceImpl;
import org.exoplatform.commons.utils.PropertyManager;
import org.exoplatform.container.PortalContainer;
import org.exoplatform.container.component.ComponentRequestLifecycle;
import org.exoplatform.extension.exchange.service.util.CalendarConverterService;
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
import org.exoplatform.services.organization.OrganizationService;
import org.exoplatform.services.organization.UserProfile;
import org.exoplatform.web.security.codec.AbstractCodec;
import org.exoplatform.web.security.codec.AbstractCodecBuilder;
import org.exoplatform.web.security.security.TokenServiceInitializationException;
import org.gatein.common.io.IOTools;
/**
*
* @author Boubaker KHANFIR
*
*/
public class IntegrationService {
public static final String USER_EXCHANGE_SERVER_URL_ATTRIBUTE = "exchange.server.url";
public static final String USER_EXCHANGE_SERVER_DOMAIN_ATTRIBUTE = "exchange.server.domain";
public static final String USER_EXCHANGE_USERNAME_ATTRIBUTE = "exchange.username";
public static final String USER_EXCHANGE_PASSWORD_ATTRIBUTE = "exchange.password";
private final static Log LOG = ExoLogger.getLogger(IntegrationService.class);
private static final String USER_EXCHANGE_HANDLED_ATTRIBUTE = "exchange.check.date";
private static final String USER_EXO_HANDLED_ATTRIBUTE = "exo.check.date";
private static final Map<String, IntegrationService> instances = new HashMap<String, IntegrationService>();
private static AbstractCodec codec;
private final String username;
private final ExchangeService service;
private final ExoStorageService exoStorageService;
private final ExchangeStorageService exchangeStorageService;
private final CorrespondenceService correspondenceService;
private final OrganizationService organizationService;
private final CalendarService calendarService;
private boolean synchIsCurrentlyRunning = false;
public IntegrationService(OrganizationService organizationService, CalendarService calendarService, ExoStorageService exoStorageService, ExchangeStorageService exchangeStorageService,
CorrespondenceService correspondenceService, ExchangeService service, String username) {
this.organizationService = organizationService;
this.calendarService = calendarService;
this.exoStorageService = exoStorageService;
this.exchangeStorageService = exchangeStorageService;
this.correspondenceService = correspondenceService;
this.service = service;
this.username = username;
// Set corresponding service to each username.
instances.put(username, this);
}
/**
* Gets user exchange instance service.
*
* @param username
* @return
*/
public static IntegrationService getInstance(String username) {
return instances.get(username);
}
/**
*
* @param folderId
* @return Exchange Folder instance based on Exchange FolderId object
* @throws Exception
*/
public CalendarFolder getExchangeCalendar(FolderId folderId) throws Exception {
return exchangeStorageService.getExchangeCalendar(service, folderId);
}
/**
*
* Synchronize Exchange Calendar identified by 'folderId' with eXo Calendar.
*
* @param folderId
* @param lastSyncDate
* @param diffTimeZone
* @throws Exception
* @return List of event IDs
*/
public List<String> synchronizeFullCalendar(FolderId folderId) throws Exception {
List<String> updatedExoEventIds = new ArrayList<String>();
CalendarFolder folder = exchangeStorageService.getExchangeCalendar(service, folderId);
// Create Calendar if not present
exoStorageService.getOrCreateUserCalendar(username, folder);
Iterable<Item> items = searchAllItems(folderId);
synchronizeAllExchangeAppointments(updatedExoEventIds, items);
deleteExoEventsOutOfSynchronization(folderId);
return updatedExoEventIds;
}
/**
*
* Synchronize Exchange Calendar identified by 'folderId' with eXo Calendar.
* The check is done for events modified since 'lastSyncDate'.
*
* @param folderId
* @param lastSyncDate
* @param updatedExoEventIDs
* @param diffTimeZone
* @throws Exception
*/
public void synchronizeModificationsOfCalendar(FolderId folderId, Date lastSyncDate, List<String> updatedExoEventIDs, int diffTimeZone) throws Exception {
// Serach modified eXo Calendar events since this date, this is used to
// force synchronization
Date exoLastSyncDate = getUserExoLastCheckDate();
if (exoLastSyncDate == null || exoLastSyncDate.before(lastSyncDate)) {
exoLastSyncDate = lastSyncDate;
}
synchronizeAppointmentsByModificationDate(folderId, lastSyncDate, updatedExoEventIDs, diffTimeZone);
synchronizeNewExoEvents(folderId, updatedExoEventIDs, exoLastSyncDate);
synchronizeExoEventsByModificationDate(folderId, updatedExoEventIDs, exoLastSyncDate);
}
/**
*
* Gets list of personnal Exchange Calendars.
*
* @return list of FolderId
* @throws Exception
*/
public List<FolderId> getAllExchangeCalendars() throws Exception {
return exchangeStorageService.getAllExchangeCalendars(service);
}
/**
* Checks if eXo associated Calendar is present.
*
* @param usename
* @return true if present.
* @throws Exception
*/
public boolean isCalendarSynchronizedWithExchange(String id) throws Exception {
return correspondenceService.getCorrespondingId(username, id) != null;
}
/**
* Checks if eXo associated Calendar is present.
*
* @param usename
* @return true if present.
* @throws Exception
*/
public boolean isCalendarPresentInExo(FolderId folderId) throws Exception {
return exoStorageService.getUserCalendar(username, folderId.getUniqueId()) != null;
}
/**
*
* Creates or updates or deletes eXo Calendar Event associated to Item, switch
* state in Exchange.
*
* @param itemEvent
* @return
* @throws Exception
*/
public List<CalendarEvent> createOrUpdateOrDelete(ItemEvent itemEvent) throws Exception {
List<CalendarEvent> updatedEvents = null;
Appointment appointment = exchangeStorageService.getAppointment(service, itemEvent.getItemId());
if (appointment == null) {
exoStorageService.deleteEventByAppointmentID(itemEvent.getItemId().getUniqueId(), username);
} else {
String eventId = correspondenceService.getCorrespondingId(username, appointment.getId().getUniqueId());
if (eventId == null) {
updatedEvents = exoStorageService.createEvent((Appointment) appointment, username, getUserExoCalenarTimeZoneSetting());
} else {
updatedEvents = exoStorageService.updateEvent((Appointment) appointment, username, getUserExoCalenarTimeZoneSetting());
}
}
return updatedEvents;
}
/**
*
* Get corresponding User Calenar from Exchange Folder Id
*
* @param folderId
* @return
* @throws Exception
*/
public Calendar getUserCalendarByExchangeFolderId(FolderId folderId) throws Exception {
return exoStorageService.getUserCalendar(username, folderId.getUniqueId());
}
/**
*
* @param eventId
* @throws Exception
*/
public void updateOrCreateExchangeCalendarEvent(Node eventNode) throws Exception {
CalendarEvent event = exoStorageService.getExoEventByNode(eventNode);
if (isCalendarSynchronizedWithExchange(event.getCalendarId())) {
List<CalendarEvent> calendarEventsToUpdateModifiedTime = new ArrayList<CalendarEvent>();
updateOrCreateExchangeCalendarEvent(event, calendarEventsToUpdateModifiedTime);
if (!calendarEventsToUpdateModifiedTime.isEmpty()) {
for (CalendarEvent calendarEvent : calendarEventsToUpdateModifiedTime) {
// This is done to not have a cyclic updates between eXo and Exchange
exoStorageService.updateModifiedDateOfEvent(username, calendarEvent);
}
}
}
}
/**
*
* @param eventId
* @throws Exception
*/
public boolean updateOrCreateExchangeCalendarEvent(String eventId) throws Exception {
CalendarEvent event = ((CalendarServiceImpl) calendarService).getDataStorage().getEvent(username, eventId);
return updateOrCreateExchangeCalendarEvent(event);
}
/**
*
* @param event
* @throws Exception
*/
public boolean updateOrCreateExchangeCalendarEvent(CalendarEvent event, List<CalendarEvent> eventsToUpdate) throws Exception {
String exoMasterId = null;
if (event.getIsExceptionOccurrence() != null && event.getIsExceptionOccurrence()) {
exoMasterId = exoStorageService.getExoEventMasterRecurenceByOriginalUUID(event.getOriginalReference());
if (exoMasterId == null) {
LOG.error("No master Id was found for occurence: " + event.getSummary() + " with recurrenceId = " + event.getRecurrenceId() + ". The event will not be updated.");
}
}
return exchangeStorageService.updateOrCreateExchangeAppointment(username, service, event, exoMasterId, getUserExoCalenarTimeZoneSetting(), eventsToUpdate);
}
/**
*
* @param event
* @throws Exception
*/
public boolean updateOrCreateExchangeCalendarEvent(CalendarEvent event) throws Exception {
return updateOrCreateExchangeCalendarEvent(event, null);
}
/**
*
* @param eventId
* @throws Exception
*/
public void deleteExchangeCalendarEvent(String eventId, String calendarId) throws Exception {
exchangeStorageService.deleteAppointmentByExoEventId(username, service, eventId, calendarId);
}
/**
*
* Handle Exchange Calendar Deletion by deleting associated eXo Calendar.
*
* @param folderId
* Exchange Calendar folderId
* @return
* @throws Exception
*/
public boolean deleteExoCalendar(FolderId folderId) throws Exception {
Folder folder = exchangeStorageService.getExchangeCalendar(service, folderId);
if (folder != null) {
if (LOG.isTraceEnabled()) {
LOG.trace("Folder was found, but event seems saying that it was deleted.");
}
return false;
}
return exoStorageService.deleteCalendar(username, folderId.getUniqueId());
}
/**
*
* @param calendarId
* @throws Exception
*/
public void deleteExchangeCalendar(String calendarId) throws Exception {
exchangeStorageService.deleteExchangeFolderByCalenarId(username, service, calendarId);
}
public void removeInstance() {
if (LOG.isTraceEnabled()) {
LOG.trace("Stop Exchange Integration Service for user: " + username);
}
instances.remove(username);
}
public List<String> synchronizeExchangeFolderState(List<FolderId> calendarFolderIds, boolean synchronizeAllExchangeFolders, boolean deleteExoCalendarOnUnsync) throws Exception {
Iterator<FolderId> iterator = calendarFolderIds.iterator();
while (iterator.hasNext()) {
FolderId folderId = (FolderId) iterator.next();
deleteExoCalendarOutOfSync(deleteExoCalendarOnUnsync, iterator, folderId);
}
List<String> updatedCalendarEventIds = null;
// synchronize added Folders
if (synchronizeAllExchangeFolders) {
List<FolderId> folderIds = exchangeStorageService.getAllExchangeCalendars(service);
for (FolderId folderId : folderIds) {
// Test if not already fully synchronized
if (!calendarFolderIds.contains(folderId)) {
// Delete eXo calendar and recreate it
exoStorageService.deleteCalendar(username, folderId.getUniqueId());
List<String> tmpUpdatedCalendarEventIds = synchronizeFullCalendar(folderId);
if (tmpUpdatedCalendarEventIds != null && !tmpUpdatedCalendarEventIds.isEmpty()) {
if (updatedCalendarEventIds == null) {
updatedCalendarEventIds = tmpUpdatedCalendarEventIds;
} else {
updatedCalendarEventIds.addAll(tmpUpdatedCalendarEventIds);
}
}
calendarFolderIds.add(folderId);
}
}
} else {
// Checks if synchronized Exchange Folders have been modified
List<FolderId> synchronizedFolderIds = getSynchronizedExchangeCalendars();
for (FolderId folderId : synchronizedFolderIds) {
// Test if not already fully synchronized
if (!calendarFolderIds.contains(folderId)) {
// Delete eXo calendar and recreate it
exoStorageService.deleteCalendar(username, folderId.getUniqueId());
List<String> tmpUpdatedCalendarEventIds = synchronizeFullCalendar(folderId);
if (tmpUpdatedCalendarEventIds != null && !tmpUpdatedCalendarEventIds.isEmpty()) {
if (updatedCalendarEventIds == null) {
updatedCalendarEventIds = tmpUpdatedCalendarEventIds;
} else {
updatedCalendarEventIds.addAll(tmpUpdatedCalendarEventIds);
}
}
calendarFolderIds.add(folderId);
}
}
Iterator<FolderId> folderIdIterator = calendarFolderIds.iterator();
while (folderIdIterator.hasNext()) {
FolderId folderId = (FolderId) folderIdIterator.next();
if (!synchronizedFolderIds.contains(folderId)) {
folderIdIterator.remove();
}
}
}
return updatedCalendarEventIds;
}
private void deleteExoCalendarOutOfSync(boolean deleteExoCalendarOnUnsync, Iterator<FolderId> iterator, FolderId folderId) throws Exception {
Folder folder = exchangeStorageService.getExchangeCalendar(service, folderId);
if (folder == null) {
// Test if the connection is ok, else the exception is thrown because of
// interrupted connection
folder = exchangeStorageService.getExchangeCalendar(service, FolderId.getFolderIdFromWellKnownFolderName(WellKnownFolderName.Calendar));
if (folder != null) {
Calendar calendar = exoStorageService.getUserCalendar(username, folderId.getUniqueId());
if (calendar != null) {
if (LOG.isTraceEnabled()) {
LOG.trace("Folder '" + folderId.getUniqueId() + "' was deleted from Exchange, stopping synchronization for this folder.");
}
if (deleteExoCalendarOnUnsync) {
exoStorageService.deleteCalendar(username, folderId.getUniqueId());
} else {
correspondenceService.deleteCorrespondingId(username, folderId.getUniqueId());
}
// Remove FolderId from synchronized folders in Scheduled Job
iterator.remove();
}
}
}
}
public List<FolderId> getSynchronizedExchangeCalendars() throws Exception {
List<FolderId> folderIds = new ArrayList<FolderId>();
List<String> folderIdsString = correspondenceService.getSynchronizedExchangeFolderIds(username);
for (String folderIdString : folderIdsString) {
folderIds.add(FolderId.getFolderIdFromString(folderIdString));
}
return folderIds;
}
public void addFolderToSynchronization(String folderIdString) throws Exception {
String calendarId = CalendarConverterService.getCalendarId(folderIdString);
correspondenceService.setCorrespondingId(username, calendarId, folderIdString);
}
public void deleteFolderFromSynchronization(String folderIdString) throws Exception {
correspondenceService.deleteCorrespondingId(username, folderIdString);
}
public synchronized void setSynchronizationStarted() {
synchIsCurrentlyRunning = true;
}
public synchronized void setSynchronizationStopped() {
synchIsCurrentlyRunning = false;
}
public synchronized boolean isSynchronizationStarted() {
return synchIsCurrentlyRunning;
}
private void deleteExoEventsOutOfSynchronization(FolderId folderId) throws Exception {
List<CalendarEvent> events = exoStorageService.getUserCalendarEvents(username, folderId.getUniqueId());
for (CalendarEvent calendarEvent : events) {
if (correspondenceService.getCorrespondingId(username, calendarEvent.getId()) == null) {
exoStorageService.deleteEvent(username, calendarEvent);
} else {
String itemId = correspondenceService.getCorrespondingId(username, calendarEvent.getId());
Appointment appointment = exchangeStorageService.getAppointment(service, itemId);
if (appointment == null) {
exoStorageService.deleteEvent(username, calendarEvent);
}
}
}
}
private void synchronizeAllExchangeAppointments(List<String> eventIds, Iterable<Item> items) throws Exception, ServiceLocalException {
for (Item item : items) {
if (item instanceof Appointment) {
List<CalendarEvent> updatedEvents = exoStorageService.createOrUpdateEvent((Appointment) item, username, getUserExoCalenarTimeZoneSetting());
if (updatedEvents != null && !updatedEvents.isEmpty()) {
for (CalendarEvent calendarEvent : updatedEvents) {
eventIds.add(calendarEvent.getId());
}
}
} else {
LOG.warn("Item bound from exchange but not of type 'Appointment':" + item.getItemClass());
}
}
}
/**
*
* Sets exo and exchange last check full synchronization operation date
*
* @param username
* @param time
* @throws Exception
*/
public void setUserLastCheckDate(long time) throws Exception {
if (organizationService instanceof ComponentRequestLifecycle) {
((ComponentRequestLifecycle) organizationService).startRequest(PortalContainer.getInstance());
}
try {
UserProfile userProfile = organizationService.getUserProfileHandler().findUserProfileByName(username);
userProfile.setAttribute(USER_EXCHANGE_HANDLED_ATTRIBUTE, "" + time);
long savedTime = userProfile.getAttribute(USER_EXO_HANDLED_ATTRIBUTE) == null ? 0 : Long.valueOf(userProfile.getAttribute(USER_EXO_HANDLED_ATTRIBUTE));
if (time > savedTime) {
userProfile.setAttribute(USER_EXO_HANDLED_ATTRIBUTE, "" + time);
}
organizationService.getUserProfileHandler().saveUserProfile(userProfile, false);
} finally {
if (organizationService instanceof ComponentRequestLifecycle) {
((ComponentRequestLifecycle) organizationService).endRequest(PortalContainer.getInstance());
}
}
}
/**
*
* Gets last check full synchronization operation date
*
* @return
* @throws Exception
*/
public Date getUserLastCheckDate() throws Exception {
if (organizationService instanceof ComponentRequestLifecycle) {
((ComponentRequestLifecycle) organizationService).startRequest(PortalContainer.getInstance());
}
try {
UserProfile userProfile = organizationService.getUserProfileHandler().findUserProfileByName(username);
long time = userProfile.getAttribute(USER_EXCHANGE_HANDLED_ATTRIBUTE) == null ? 0 : Long.valueOf(userProfile.getAttribute(USER_EXCHANGE_HANDLED_ATTRIBUTE));
Date lastSyncDate = null;
if (time > 0) {
lastSyncDate = new Date(time);
}
return lastSyncDate;
} finally {
if (organizationService instanceof ComponentRequestLifecycle) {
((ComponentRequestLifecycle) organizationService).endRequest(PortalContainer.getInstance());
}
}
}
/**
*
* Sets exo last check operation date.
*
* @param username
* @param time
* @throws Exception
*/
public void setUserExoLastCheckDate(long time) throws Exception {
if (organizationService instanceof ComponentRequestLifecycle) {
((ComponentRequestLifecycle) organizationService).startRequest(PortalContainer.getInstance());
}
try {
UserProfile userProfile = organizationService.getUserProfileHandler().findUserProfileByName(username);
long savedTime = userProfile.getAttribute(USER_EXO_HANDLED_ATTRIBUTE) == null ? 0 : Long.valueOf(userProfile.getAttribute(USER_EXO_HANDLED_ATTRIBUTE));
if (savedTime <= 0) {
if (LOG.isTraceEnabled()) {
LOG.trace("User '" + username + "' exo last check time was not set before, may be the synhronization was not run before or an error occured in the meantime.");
}
} else {
userProfile.setAttribute(USER_EXO_HANDLED_ATTRIBUTE, "" + time);
organizationService.getUserProfileHandler().saveUserProfile(userProfile, false);
}
} finally {
if (organizationService instanceof ComponentRequestLifecycle) {
((ComponentRequestLifecycle) organizationService).endRequest(PortalContainer.getInstance());
}
}
}
/**
*
* Gets exo last check operation date
*
* @return
* @throws Exception
*/
public Date getUserExoLastCheckDate() throws Exception {
if (organizationService instanceof ComponentRequestLifecycle) {
((ComponentRequestLifecycle) organizationService).startRequest(PortalContainer.getInstance());
}
try {
UserProfile userProfile = organizationService.getUserProfileHandler().findUserProfileByName(username);
long time = userProfile.getAttribute(USER_EXO_HANDLED_ATTRIBUTE) == null ? 0 : Long.valueOf(userProfile.getAttribute(USER_EXO_HANDLED_ATTRIBUTE));
Date lastSyncDate = null;
if (time > 0) {
lastSyncDate = new Date(time);
}
return lastSyncDate;
} finally {
if (organizationService instanceof ComponentRequestLifecycle) {
((ComponentRequestLifecycle) organizationService).endRequest(PortalContainer.getInstance());
}
}
}
/**
*
* @param organizationService
* @param username
* @param name
* @param value
* @throws Exception
*/
public static void setUserArrtibute(OrganizationService organizationService, String username, String name, String value) throws Exception {
if (organizationService instanceof ComponentRequestLifecycle) {
((ComponentRequestLifecycle) organizationService).startRequest(PortalContainer.getInstance());
}
try {
if (USER_EXCHANGE_PASSWORD_ATTRIBUTE.equals(name)) {
value = encodePassword(value);
}
UserProfile userProfile = organizationService.getUserProfileHandler().findUserProfileByName(username);
if (userProfile == null) {
userProfile = organizationService.getUserProfileHandler().createUserProfileInstance(username);
organizationService.getUserProfileHandler().saveUserProfile(userProfile, true);
}
userProfile.setAttribute(name, value);
organizationService.getUserProfileHandler().saveUserProfile(userProfile, false);
} finally {
if (organizationService instanceof ComponentRequestLifecycle) {
((ComponentRequestLifecycle) organizationService).endRequest(PortalContainer.getInstance());
}
}
}
/**
*
* @param organizationService
* @param username
* @param name
* @return
* @throws Exception
*/
public static String getUserArrtibute(OrganizationService organizationService, String username, String name) throws Exception {
if (organizationService instanceof ComponentRequestLifecycle) {
((ComponentRequestLifecycle) organizationService).startRequest(PortalContainer.getInstance());
}
try {
UserProfile userProfile = organizationService.getUserProfileHandler().findUserProfileByName(username);
String value = null;
if (userProfile != null) {
value = userProfile.getAttribute(name);
if (value != null && USER_EXCHANGE_PASSWORD_ATTRIBUTE.equals(name)) {
value = decodePassword(value);
}
}
return value;
} finally {
if (organizationService instanceof ComponentRequestLifecycle) {
((ComponentRequestLifecycle) organizationService).endRequest(PortalContainer.getInstance());
}
}
}
public ExchangeService getService() {
return service;
}
/**
* This method returns User exo calendar TimeZone settings. This have to be
* called each synchronization, the timeZone may be changed from call to
* another.
*
* @return User exo calendar TimeZone settings
*/
private TimeZone getUserExoCalenarTimeZoneSetting() {
try {
CalendarSetting calendarSetting = calendarService.getCalendarSetting(username);
return TimeZone.getTimeZone(calendarSetting.getTimeZone());
} catch (Exception e) {
LOG.error("Error while getting user '" + username + "'Calendar TimeZone setting, use default, this may cause some inconsistance.");
return TimeZone.getDefault();
}
}
private void synchronizeExoEventsByModificationDate(FolderId folderId, List<String> updatedExoEventIDs, Date exoLastSyncDate) throws Exception {
List<CalendarEvent> modifiedCalendarEvents = searchCalendarEventsModifiedSince(getUserCalendarByExchangeFolderId(folderId), exoLastSyncDate);
for (CalendarEvent calendarEvent : modifiedCalendarEvents) {
// If modified with synchronization, ignore
if (updatedExoEventIDs.contains(calendarEvent.getId())) {
continue;
}
String exoMasterId = null;
if (calendarEvent.getIsExceptionOccurrence() != null && calendarEvent.getIsExceptionOccurrence()) {
exoMasterId = exoStorageService.getExoEventMasterRecurenceByOriginalUUID(calendarEvent.getOriginalReference());
if (exoMasterId == null) {
LOG.error("No master Id was found for occurence: " + calendarEvent.getSummary() + " with recurrenceId = " + calendarEvent.getRecurrenceId() + ". The event will not be updated.");
}
}
boolean deleteEvent = exchangeStorageService.updateOrCreateExchangeAppointment(username, service, calendarEvent, exoMasterId, getUserExoCalenarTimeZoneSetting(), null);
if (deleteEvent) {
exoStorageService.deleteEvent(username, calendarEvent);
}
updatedExoEventIDs.add(calendarEvent.getId());
}
}
@SuppressWarnings("deprecation")
private void synchronizeNewExoEvents(FolderId folderId, List<String> updatedExoEventIDs, Date exoLastSyncDate) throws Exception {
// Search for existant Appointments in Exchange but not in eXo
Iterable<CalendarEvent> unsynchronizedEvents = searchUnsynchronizedAppointments(username, folderId.getUniqueId());
for (CalendarEvent calendarEvent : unsynchronizedEvents) {
// To not have redendance
if (updatedExoEventIDs != null && updatedExoEventIDs.contains(calendarEvent.getId())) {
continue;
}
if (calendarEvent.getLastUpdatedTime() != null) {
if (calendarEvent.getLastUpdatedTime().after(exoLastSyncDate)) {
String exoMasterId = null;
if (calendarEvent.getIsExceptionOccurrence() != null && calendarEvent.getIsExceptionOccurrence()) {
exoMasterId = exoStorageService.getExoEventMasterRecurenceByOriginalUUID(calendarEvent.getOriginalReference());
if (exoMasterId == null) {
LOG.error("No master Id was found for occurence: " + calendarEvent.getSummary() + " with recurrenceId = " + calendarEvent.getRecurrenceId() + ". The event will not be updated.");
continue;
}
}
boolean deleteEvent = exchangeStorageService.updateOrCreateExchangeAppointment(username, service, calendarEvent, exoMasterId, getUserExoCalenarTimeZoneSetting(), null);
if (deleteEvent) {
exoStorageService.deleteEvent(username, calendarEvent);
}
if (updatedExoEventIDs != null) {
updatedExoEventIDs.add(calendarEvent.getId());
}
} else {
exoStorageService.deleteEvent(username, calendarEvent);
}
}
}
}
private void synchronizeAppointmentsByModificationDate(FolderId folderId, Date lastSyncDate, List<String> updatedExoEventIDs, int diffTimeZone) throws Exception, ServiceLocalException,
ParseException {
Iterable<Item> items = searchAllAppointmentsModifiedSince(folderId, lastSyncDate, diffTimeZone);
// Search for modified Appointments in Exchange, since last check date.
for (Item item : items) {
if (item instanceof Appointment) {
// Test if there is a modification conflict
CalendarEvent event = exoStorageService.getEventByAppointmentId(username, item.getId().getUniqueId());
if (event != null) {
if (updatedExoEventIDs != null && updatedExoEventIDs.contains(event.getId())) {
// Already updated by previous operation
continue;
}
@SuppressWarnings("deprecation")
Date eventModifDate = CalendarConverterService.convertDateToUTC(event.getLastUpdatedTime());
Date itemModifDate = item.getLastModifiedTime();
if (itemModifDate.after(eventModifDate)) {
List<CalendarEvent> updatedEvents = exoStorageService.updateEvent((Appointment) item, username, getUserExoCalenarTimeZoneSetting());
if (updatedEvents != null && !updatedEvents.isEmpty() && updatedExoEventIDs != null) {
for (CalendarEvent calendarEvent : updatedEvents) {
updatedExoEventIDs.add(calendarEvent.getId());
}
}
}
} else {
List<CalendarEvent> updatedEvents = exoStorageService.createEvent((Appointment) item, username, getUserExoCalenarTimeZoneSetting());
if (updatedEvents != null && !updatedEvents.isEmpty() && updatedExoEventIDs != null) {
for (CalendarEvent calendarEvent : updatedEvents) {
updatedExoEventIDs.add(calendarEvent.getId());
}
}
}
} else {
LOG.warn("Item bound from exchange but not of type 'Appointment':" + item.getItemClass());
}
}
}
private Iterable<CalendarEvent> searchUnsynchronizedAppointments(String username, String folderId) throws Exception {
List<CalendarEvent> calendarEvents = exoStorageService.getUserCalendarEvents(username, folderId);
Iterator<CalendarEvent> calendarEventsIterator = calendarEvents.iterator();
while (calendarEventsIterator.hasNext()) {
CalendarEvent calendarEvent = calendarEventsIterator.next();
String itemId = correspondenceService.getCorrespondingId(username, calendarEvent.getId());
if (itemId == null) {
// Item was detected, and will be created
continue;
}
Appointment appointment = exchangeStorageService.getAppointment(service, ItemId.getItemIdFromString(itemId));
if (appointment != null) {
calendarEventsIterator.remove();
}
}
return calendarEvents;
}
private List<Item> searchAllItems(FolderId parentFolderId) throws Exception {
ItemView view = new ItemView(1000);
view.setPropertySet(new PropertySet(BasePropertySet.FirstClassProperties));
FindItemsResults<Item> findResults = service.findItems(parentFolderId, view);
if (LOG.isTraceEnabled()) {
LOG.trace("Exchange user calendar '" + username + "', items found: " + findResults.getTotalCount());
}
return findResults.getItems();
}
private List<CalendarEvent> searchCalendarEventsModifiedSince(Calendar calendar, Date date) throws Exception {
if (date == null) {
return exoStorageService.getAllExoEvents(username, calendar);
}
return exoStorageService.findExoEventsModifiedSince(username, calendar, date);
}
private List<Item> searchAllAppointmentsModifiedSince(FolderId parentFolderId, Date date, int diffTimeZone) throws Exception {
if (date == null) {
return searchAllItems(parentFolderId);
}
// Exchange system dates are saved using UTC timezone independing of User
// Calendar timezone, so we have to get the diff with eXo Server TimeZone
// and Exchange to make search queries
java.util.Calendar calendar = java.util.Calendar.getInstance();
calendar.setTime(date);
calendar.add(java.util.Calendar.MINUTE, diffTimeZone);
calendar.add(java.util.Calendar.SECOND, 1);
ItemView view = new ItemView(100);
view.setPropertySet(new PropertySet(BasePropertySet.FirstClassProperties));
FindItemsResults<Item> findResults = service.findItems(parentFolderId, new SearchFilter.IsGreaterThan(ItemSchema.LastModifiedTime, calendar.getTime()), view);
if (LOG.isTraceEnabled()) {
LOG.trace("Exchange user calendar '" + username + "', items found: " + findResults.getTotalCount());
}
return findResults.getItems();
}
private static void initCodec() throws Exception {
String builderType = PropertyManager.getProperty("gatein.codec.builderclass");
Map<String, String> config = new HashMap<String, String>();
if (builderType != null) {
// If there is config for codec in configuration.properties, we read the
// config parameters from config file
// referenced in configuration.properties
String configFile = PropertyManager.getProperty("gatein.codec.config");
InputStream in = null;
try {
File f = new File(configFile);
in = new FileInputStream(f);
Properties properties = new Properties();
properties.load(in);
for (Map.Entry<?, ?> entry : properties.entrySet()) {
config.put((String) entry.getKey(), (String) entry.getValue());
}
config.put("gatein.codec.config.basedir", f.getParentFile().getAbsolutePath());
} catch (IOException e) {
throw new TokenServiceInitializationException("Failed to read the config parameters from file '" + configFile + "'.", e);
} finally {
IOTools.safeClose(in);
}
} else {
// If there is no config for codec in configuration.properties, we
// generate key if it does not exist and setup the
// default config
builderType = "org.exoplatform.web.security.codec.JCASymmetricCodecBuilder";
String gtnConfDir = PropertyManager.getProperty("gatein.conf.dir");
if (gtnConfDir == null || gtnConfDir.length() == 0) {
throw new TokenServiceInitializationException("'gatein.conf.dir' property must be set.");
}
File f = new File(gtnConfDir + "/codec/codeckey.txt");
if (!f.exists()) {
File codecDir = f.getParentFile();
if (!codecDir.exists()) {
codecDir.mkdir();
}
OutputStream out = null;
try {
KeyGenerator keyGen = KeyGenerator.getInstance("AES");
keyGen.init(128);
SecretKey key = keyGen.generateKey();
KeyStore store = KeyStore.getInstance("JCEKS");
store.load(null, "gtnStorePass".toCharArray());
store.setEntry("gtnKey", new KeyStore.SecretKeyEntry(key), new KeyStore.PasswordProtection("gtnKeyPass".toCharArray()));
out = new FileOutputStream(f);
store.store(out, "gtnStorePass".toCharArray());
} catch (Exception e) {
throw new TokenServiceInitializationException(e);
} finally {
IOTools.safeClose(out);
}
}
config.put("gatein.codec.jca.symmetric.keyalg", "AES");
config.put("gatein.codec.jca.symmetric.keystore", "codeckey.txt");
config.put("gatein.codec.jca.symmetric.storetype", "JCEKS");
config.put("gatein.codec.jca.symmetric.alias", "gtnKey");
config.put("gatein.codec.jca.symmetric.keypass", "gtnKeyPass");
config.put("gatein.codec.jca.symmetric.storepass", "gtnStorePass");
config.put("gatein.codec.config.basedir", f.getParentFile().getAbsolutePath());
}
try {
codec = Class.forName(builderType).asSubclass(AbstractCodecBuilder.class).newInstance().build(config);
LOG.info("Initialized CookieTokenService.codec using builder " + builderType);
} catch (Exception e) {
throw new TokenServiceInitializationException("Could not initialize CookieTokenService.codec.", e);
}
}
private static String decodePassword(String password) {
try {
if (codec == null) {
initCodec();
}
password = codec.decode(password);
} catch (Exception e) {
LOG.warn("Error while decoding password, it will be used in plain text", e);
}
return password;
}
private static String encodePassword(String password) {
try {
if (codec == null) {
initCodec();
}
password = codec.encode(password);
} catch (Exception e) {
LOG.warn("Error while encoding password, it will be used in plain text", e);
}
return password;
}
}